package com.zp.elasticsearch.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zp.elasticsearch.exception.ElasticSearchException;
import com.zp.elasticsearch.vo.ElasticEntity;
import com.zp.elasticsearch.vo.ExampleEntity;
import org.apache.http.HttpHost;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Component
public class ElasticSearchClientImpl implements ElasticSearchClient,InitializingBean {
    @Value("${es.ip}")
    private  String esIp;

    @Value("${es.port}")
    private  int esPort;

    @Value("${server.port}")
    private int serverPort;

    private RestHighLevelClient client;
    private ObjectMapper objectMapper;

    public ElasticSearchClientImpl() {

    }

    @Override
    public void save(ElasticEntity entity) {
        try {
            client.index(createIndexRequest(entity));
        } catch (IOException e) {
            throw new ElasticSearchException(e.getMessage());
        }
    }

    @Override
    public ExampleEntity findById(String id) {
        try {
            GetResponse response = client.get(createGetRequest("examples", "example", id));
            return objectMapper.readValue(response.getSourceAsBytes(), ExampleEntity.class);
        } catch (IOException e) {
            throw new ElasticSearchException(e.getMessage());
        }
    }

    @Override
    public List<ExampleEntity> search(QueryBuilder queryBuilder) {
        try {
            SearchResponse searchResponse = client.search(createSearchRequest(queryBuilder));
            List<ExampleEntity> result = new ArrayList<>();
            searchResponse.getHits().forEach(hit -> {
                try {
                    ExampleEntity e = objectMapper.readValue(hit.getSourceAsString(), ExampleEntity.class);
                    result.add(e);
                } catch (IOException e) {
                    throw new ElasticSearchException(e.getMessage());
                }
            });
            return result;
        } catch (IOException e) {
            throw new ElasticSearchException(e.getMessage());
        }
    }

    @Override
    public Object delById(String id) {
        return null;
    }

    private SearchRequest createSearchRequest(QueryBuilder queryBuilder) {
        SearchRequest searchRequest = new SearchRequest("examples");
        searchRequest.types("example");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        searchRequest.source(searchSourceBuilder);
        return searchRequest;
    }

    private GetRequest createGetRequest(String index, String type, String id) {
        return new GetRequest(index, type, id);
    }

    private IndexRequest createIndexRequest(ElasticEntity entity) {
        try {
            byte[] json = objectMapper.writeValueAsBytes(entity);
            IndexRequest indexRequest = new IndexRequest(entity.getIndex(), entity.getType(), entity.getId());
            indexRequest.source(json, XContentType.JSON);
            return indexRequest;
        } catch (JsonProcessingException e) {
            throw new ElasticSearchException("An error occurred when parsing the object with id: "
                    + entity.getId() + ". Error was: " + e.getMessage());
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        initClient();
    }

    private void initClient() {
        client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost(esIp, esPort, "http")// dev环境
                )
        );
        objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
}
